#include "./../../../include/online/WebPageQuery/WebPage.h"
#include "./../../../include/online/Tools/Configuration.h"
#include "./../../../include/online/Tools/CppJieba.h"
#include <iostream>
#include <map>
#include <regex>
#include <algorithm>

using namespace std;

// 检查是否是UTF-8字符串并修复UTF-8字符串中的无效字符
static int isValidUTF8Character(string *str)
{
    int i, f_size = str->size();
    unsigned char c, c2, c3, c4;
    string to;
    to.reserve(f_size);
    for (i = 0; i < f_size; i++)
    {
        c = (unsigned char)(*str)[i];
        if (c < 32)
        {
            if (c == 9 || c == 10 || c == 13)
            {
                to.append(1, c);
            }
        }
        else if (c < 127)
        {
            to.append(1, c);
        }
        else if (c < 160)
        {
            if (c2 == 128)
            {
                to.append(1, 226);
                to.append(1, 130);
                to.append(1, 172);
            }
            if (c2 == 133)
            {
                to.append(1, 10);
                to.append(1, 13);
            }
        }
        else if (c < 192)
        {
            to.append(1, (unsigned char)194);
            to.append(1, c);
        }
        else if (c < 194)
        {
            to.append(1, (unsigned char)195);
            to.append(1, c - 64);
        }
        else if (c < 224)
        {
            c2 = (unsigned char)(*str)[i + 1];
            if (c2 > 127 && c2 < 192)
            {
                if (c == 194 && c2 < 160)
                {
                    ;
                }
                else
                {
                    to.append(1, c);
                    to.append(1, c2);
                }
                i++;
            }
            else
            {
                to.append(1, (unsigned char)195);
                to.append(1, c - 64);
            }
        }
        else if (c < 240)
        {
            c2 = (unsigned char)(*str)[i + 1];
            c3 = (unsigned char)(*str)[i + 2];
            if (c2 > 127 && c2 < 192 && c3 > 127 && c3 < 192)
            {
                to.append(1, c);
                to.append(1, c2);
                to.append(1, c3);
                i += 2;
            }
            else
            {
                to.append(1, (unsigned char)195);
                to.append(1, c - 64);
            }
        }
        else if (c < 245)
        {
            c2 = (unsigned char)(*str)[i + 1];
            c3 = (unsigned char)(*str)[i + 2];
            c4 = (unsigned char)(*str)[i + 3];
            if (c2 > 127 && c2 < 192 && c3 > 127 && c3 < 192 && c4 > 127 && c4 < 192)
            {
                to.append(1, c);
                to.append(1, c2);
                to.append(1, c3);
                to.append(1, c4);
                i += 3;
            }
            else
            {
                to.append(1, (unsigned char)195);
                to.append(1, c - 64);
            }
        }
        else if (c < 256)
        {
            to.append(1, (unsigned char)195);
            to.append(1, c - 64);
        }
        else
        {
            cout << "WTF? more than 256 values per Byte ? (" << (unsigned int)c << ")" << endl;
        }
    }
    *str = to;
    return 1;
}

size_t getByteNum_UTF8(const char byte)
{
    int byteNum = 0;
    for (size_t i = 0; i < 6; ++i)
    {
        if (byte & (1 << (7 - i)))
            ++byteNum;
        else
            break;
    }
    return byteNum == 0 ? 1 : byteNum;
}

bool isUTF8Valid(char ch)
{
    if ((ch & 0xC0) != 0x80)
    {
        return true;
    }
    return false;
}

WebPage::WebPage(string doc)
: _doc(doc)
{
    isValidUTF8Character(&_doc);
}

WebPage::~WebPage()
{
    
}

// 获取文章的id
int WebPage::getDoiId()
{
    return _docId;
}

// 获取文章的标题
string WebPage::getTitle()
{
    return _docTitle;
}

// 获取文章的链接
string WebPage::getDocUrl()
{
    return _docUrl;
}

// 获取文章的摘要
string WebPage::getSummary(const vector<string> &queryWords)
{
    string strTemp = _docContent + _docSummary;
    if (strTemp.empty())
    {
        return "";
    }

    _docSummary = "";

    for (const auto &query : queryWords)
    {
        size_t pos = 0;
        int number = 3;

        while (pos != std::string::npos && number > 0)
        {
            pos = strTemp.find(query, pos);
            if (pos != std::string::npos)
            {
                size_t start = (pos >= 30) ? (pos - 30) : 0; // 获取关键词前面十个汉字的起始位置
                size_t num = 0;
                for (int i = 0; i < 3; i++)
                {
                    if ((0xe0 & (strTemp[start + i])) == 0xe0)
                    {
                        start += i;
                        break;
                    }
                }

                for (int count = 0; count < 15 && (pos + count) < strTemp.length(); count++)
                {
                    if (isUTF8Valid(strTemp[pos + num]))
                        num += getByteNum_UTF8(strTemp[pos + num]);
                    else
                        num++;
                }

                if (_docSummary.length() + num + 3 * number <= 1000)
                {
                    _docSummary += strTemp.substr(start, 510); // 获取关键词前面十个汉字及后续510个字符
                    for (int i = 0; i < 2; i++)
                    {
                        char ch = _docSummary[_docSummary.size() - 5 + i];
                        if ((0xe0 & ch) == 0xe0)
                        {
                            _docSummary.erase(_docSummary.size() - 2 + i);
                            break;
                        }
                        else if ((ch & 0xc0) != 0x80)
                        {
                            _docSummary.erase(_docSummary.size() - 5 + i);
                            break;
                        }
                    }
                    _docSummary += "...";
                    pos += 510;
                    number--;
                }
                else
                {
                    break;
                }
            }
        }
    }

    for (size_t i = 0; i < queryWords.size(); ++i)
    {
        size_t pos = 0;
        while (1)
        {
            pos = _docSummary.find(queryWords[i], pos);
            if (pos != std::string::npos)
            {
                _docSummary.insert(pos + queryWords[i].size(), "\033[0m");
                _docSummary.insert(pos, "\033[;31m");
                pos = pos + queryWords[i].size() + string("\033[0m").size() + string("\033[;31m").size();
            }
            else
                break;
        }
    }

    return _docSummary;
}

// 获取文章的词频统计map
unordered_map<string, int> WebPage::getWordMap()
{
    Configuration* conf = Configuration::getInstance();

    // 对文章进行分词
    CppJieba *cppjieba = CppJieba::getInstance();
    vector<string> words = cppjieba->cut(_doc);

    // 遍历分词结果
    for(auto& word:words)
    {
        if(conf->isStopWord(word))   // 是停用词
        {
            continue;
        }
        ++_wordsMap[word];
    }
    return _wordsMap;
}

// 对格式化文章进行处理
void WebPage::processDoc()
{
    regex idPattern("<docid>(\\d+)</docid>");
    smatch matches;

    if (regex_search(_doc, matches, idPattern))
    {
        _docId = stoi(matches[1].str());
    }
    else
    {
        _docId = 0;
    }

    // 获取文章标题
    _docTitle=_doc.substr(_doc.find("<title>") + 7, _doc.find("</title>") - _doc.find("<title>") - 7);
    
    // 获取文章链接
    _docUrl=_doc.substr(_doc.find("<link>") + 6, _doc.find("</link>") - _doc.find("<link>") - 6);

    // 获取文章内容
    _docContent=_doc.substr(_doc.find("<content>") + 9, _doc.find("</content>") - _doc.find("<content>") - 9);

    // 测试
    // cout << "docId: " << _docId << endl;
    // cout << "标题：" << _docTitle << endl;
    // cout << "链接：" << _docUrl << endl;
    // cout << "内容：" << _docContent << endl;
    // cout << "文档摘要：" << _docSummary << endl;
}

// 统计词频最高的二十个词语
void WebPage::countTopK()
{
    // 将每篇文档的所有词语和词频，按词频从小到大插入(map默认按key从小到大排列)
    map<int, string> maxWords;
    if (!_wordsMap.empty())
    {
        for (auto &ele : _wordsMap)
        {
            if (!ele.first.empty())
            {
                maxWords[ele.second] = ele.first;
            }
        }
    }

    // 从后向前遍历
    auto it = maxWords.end();
    for (int i = 1; i <= 20; ++i)
    {
        if (maxWords.empty())
        {
            break;
        }

        --it;
        if (it == maxWords.begin())
        {
            _topWords.push_back(it->second);
            break;
        }
        else
        {
            _topWords.push_back(it->second);
        }
    }
    return;
}